﻿using SeeSharpTools.Demo.Properties;
using SeeSharpTools.JY.DSP.Measurements;
using SeeSharpTools.JY.GUI;
using Sunny.UI;
using System;
using System.Drawing;
using System.Windows.Forms;

namespace SeeSharpTools.Demo
{
    public partial class FormPulse : UIPage
    {
        /// <summary>
        /// Data plotted
        /// </summary>
        private double[] _ys;

        private const double sampleRate = 1000;

        /// <summary>
        /// X's increment
        /// </summary>
        private double _increment => 1 / sampleRate;

        /// <summary>
        /// High low state setting
        /// </summary>
        private HighLowStateSetting _stateSetting;

        /// <summary>
        /// Pulse reference level
        /// </summary>
        private PulseReferenceLevel _refLevelSetting;

        /// <summary>
        /// Number of pulses
        /// </summary>
        private int _pulseNumber;

        /// <summary>
        /// Edge Polarity
        /// </summary>
        private EdgePolarity _edgePolarity;

        /// <summary>
        ///  Pulse Polarity;
        /// </summary>
        private PulsePolarity _pulsePolarity;

        /// <summary>
        /// EasyChartX tab cursors show important data information.
        /// </summary>
        private TabCursor _highLevelCursor = new TabCursor();

        private TabCursor _lowLevelCursor = new TabCursor();
        private TabCursor _midLevelCursor = new TabCursor();

        private TabCursor _firstCursor = new TabCursor();
        private TabCursor _secondCursor = new TabCursor();
        private TabCursor _thirdCursor = new TabCursor();

        private TabCursor _edgeStartCursor = new TabCursor();
        private TabCursor _edgeEndCursor = new TabCursor();

        public FormPulse()
        {
            InitializeComponent();

            uiComboBox_ComputeMethod.Items.AddRange(Enum.GetNames(typeof(HighLowStateMethod)));
            uiComboBox_ComputeMethod.SelectedIndex = 0;
            uiComboBox_PulsePolarity.Items.AddRange(Enum.GetNames(typeof(PulsePolarity)));
            uiComboBox_PulsePolarity.SelectedIndex = 0;
            uiComboBox_EdgePolarity.Items.AddRange(Enum.GetNames(typeof(EdgePolarity)));
            uiComboBox_EdgePolarity.SelectedIndex = 0;
            uiComboBox_PulseIndex.SelectedIndex = 0;

            InitializeCursors();
        }

        /// <summary>
        /// Initialize EastChart Cursors for display;
        /// </summary>
        private void InitializeCursors()
        {
            _highLevelCursor.Color = Color.Orange;
            _highLevelCursor.Name = "HighLevel";
            _highLevelCursor.Direction = SeeSharpTools.JY.GUI.TabCursorUtility.TabCursorDirection.Horizontal;
            _lowLevelCursor.Color = Color.Orange;
            _lowLevelCursor.Name = "LowLevel";
            _lowLevelCursor.Direction = SeeSharpTools.JY.GUI.TabCursorUtility.TabCursorDirection.Horizontal;
            _midLevelCursor.Color = Color.Orange;
            _midLevelCursor.Name = "MidLevel";
            _midLevelCursor.Direction = SeeSharpTools.JY.GUI.TabCursorUtility.TabCursorDirection.Horizontal;

            _firstCursor.Color = Color.Green;
            _firstCursor.Name = "FirstEdge";
            _firstCursor.Direction = SeeSharpTools.JY.GUI.TabCursorUtility.TabCursorDirection.Vertical;
            _secondCursor.Color = Color.Green;
            _secondCursor.Name = "SecondEdge";
            _secondCursor.Direction = SeeSharpTools.JY.GUI.TabCursorUtility.TabCursorDirection.Vertical;
            _thirdCursor.Color = Color.Green;
            _thirdCursor.Name = "ThirdEdge";
            _thirdCursor.Direction = SeeSharpTools.JY.GUI.TabCursorUtility.TabCursorDirection.Vertical;

            _edgeStartCursor.Color = Color.DeepPink;
            _edgeStartCursor.Name = "EdgeStart";
            _edgeStartCursor.Direction = SeeSharpTools.JY.GUI.TabCursorUtility.TabCursorDirection.Vertical;
            _edgeEndCursor.Color = Color.DeepPink;
            _edgeEndCursor.Name = "EdgeEnd";
            _edgeEndCursor.Direction = SeeSharpTools.JY.GUI.TabCursorUtility.TabCursorDirection.Vertical;

            easyChartX_signalMeasurement.TabCursors.Add(_highLevelCursor);
            easyChartX_signalMeasurement.TabCursors.Add(_lowLevelCursor);
            easyChartX_signalMeasurement.TabCursors.Add(_firstCursor);
            easyChartX_signalMeasurement.TabCursors.Add(_secondCursor);
            easyChartX_signalMeasurement.TabCursors.Add(_thirdCursor);
            easyChartX_signalMeasurement.TabCursors.Add(_midLevelCursor);
            easyChartX_signalMeasurement.TabCursors.Add(_edgeStartCursor);
            easyChartX_signalMeasurement.TabCursors.Add(_edgeEndCursor);
        }

        /// <summary>
        /// Load data from square.txt in resources.resx
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private double[] LoadDataFromResources()
        {
            string path = Resources.Square;
            return ReadDataFile(path);
        }

        /// <summary>
        /// Read Data line by line and return double array
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private static double[] ReadDataFile(string path)
        {
            string[] lines = path.Split('\n');

            double[] data = new double[lines.Length];

            for (int i = 0; i < lines.Length; i++)
            {
                data[i] = double.Parse(lines[i].Split('\t')[1].Trim());
            }

            return data;
        }

        private void uiButton_Start_Click(object sender, EventArgs e)
        {
            _ys = LoadDataFromResources();

            _pulseNumber = Convert.ToInt32(uiComboBox_PulseIndex.Text);
            _edgePolarity = (EdgePolarity)Enum.Parse(typeof(EdgePolarity), uiComboBox_EdgePolarity.Text);
            _pulsePolarity = (PulsePolarity)Enum.Parse(typeof(PulsePolarity), uiComboBox_PulsePolarity.Text);

            HighLowStateMethod stateMethod = (HighLowStateMethod)Enum.Parse(typeof(HighLowStateMethod), uiComboBox_ComputeMethod.Text);
            int histogramSize = uiIntegerUpDown_HistogramSize.Value;
            _stateSetting = new HighLowStateSetting()
            {
                Method = stateMethod,
                HistogramSize = histogramSize
            };

            _refLevelSetting = new PulseReferenceLevel()
            {
                High = 0.9,
                Low = 0.1,
                Middle = 0.5,
                Unit = PulseReferenceUnit.Percentage
            };

            // Plot square wave data with an increment;
            easyChartX_signalMeasurement.Plot(_ys, 0, _increment);

            AmplitudeLevelAnalysis();

            PulseMeasurement();

            PeriodAnalyis();

            CycleRmsMeanAnalysis();

            TransitionMeasurement();
        }

        /// <summary>
        /// Analyze amplitude level.
        /// </summary>
        private void AmplitudeLevelAnalysis()
        {
            try
            {
                WaveformMeasurements.AmplitudeLevelAnalysis(_ys, _stateSetting, out double amplitude,
                    out double highLevel, out double lowLevel);
                uiTextBox_Amplitude.Text = amplitude.ToString("F6");
                uiTextBox_HighLevel.Text = highLevel.ToString("F6");
                uiTextBox_LowLevel.Text = lowLevel.ToString("F6");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Measure pulse.
        /// </summary>
        private void PulseMeasurement()
        {
            try
            {
                WaveformMeasurements.PulseMeasurement(_ys, _increment, _stateSetting, _pulsePolarity, _refLevelSetting, _pulseNumber, out double period, out double pulseWidth, out double dutyCycle, out PulseMeasurementInfo measurementInfo);

                // Set EasychartX cursor values
                _midLevelCursor.YValue = measurementInfo.PulseReferenceLevel.Middle;
                _firstCursor.XValue = measurementInfo.PulseCenter - pulseWidth / 2;
                _secondCursor.XValue = measurementInfo.PulseCenter + pulseWidth / 2;
                _thirdCursor.XValue = _firstCursor.XValue + period;

                uiTextBox_Period.Text = period.ToString("F6");
                uiTextBox_DutyCycle.Text = (dutyCycle * 100).ToString("F3") + "%";
                uiTextBox_PulseWidth.Text = pulseWidth.ToString("F6");

                easyChartX_signalMeasurement.AddDataMarker(new double[] { _firstCursor.XValue, _secondCursor.XValue, _thirdCursor.XValue },
                                                           new double[] { measurementInfo.PulseReferenceLevel.Middle,
                                                                      measurementInfo.PulseReferenceLevel.Middle,
                                                                      measurementInfo.PulseReferenceLevel.Middle },
                                                           Color.AliceBlue,
                                                           DataMarkerType.Cross);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Analyze period
        /// </summary>
        private void PeriodAnalyis()
        {
            try
            {
                WaveformMeasurements.PeriodAnalysis(_ys, _increment, _stateSetting, PulsePolarity.High, _refLevelSetting, out PeriodAnalysisResult periodResult, out PeriodAnalysisResult dutyCycleResult, out PeriodAnalysisResult pulseResult, out MeasurementInfo periodMeasurementInfo);

                uiTextBox_PeriodMax.Text = periodResult.Maximum.ToString("F6");
                uiTextBox_PeriodMin.Text = periodResult.Minimum.ToString("F6");
                uiTextBox_PeriodAvg.Text = periodResult.Average.ToString("F6");

                uiTextBox_DutycycleMax.Text = (dutyCycleResult.Maximum * 100).ToString("F3") + "%";
                uiTextBox_DutycycleMin.Text = (dutyCycleResult.Minimum * 100).ToString("F3") + "%";
                uiTextBox_DutycycleaAvg.Text = (dutyCycleResult.Average * 100).ToString("F3") + "%";

                uiTextBox_PulseWidthMax.Text = pulseResult.Maximum.ToString("F6");
                uiTextBox_PulseWidthMin.Text = pulseResult.Minimum.ToString("F6");
                uiTextBox_PulseWidthAvg.Text = pulseResult.Average.ToString("F6");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Analyze cycle rms mean.
        /// </summary>
        private void CycleRmsMeanAnalysis()
        {
            try
            {
                WaveformMeasurements.CycleRmsMeanAnalysis(_ys, _increment, _stateSetting, _refLevelSetting, uiComboBox_PulseIndex.SelectedIndex + 1, out double rmsResults, out double meanResults, out MeasurementInfo cycleAnalysisInfo);

                // Display formatted data
                // F6 - displaying 6 floating digits
                // F3- displaying 3 floating digits
                uiTextBox_CycleRMS.Text = rmsResults.ToString("F6");
                uiTextBox_CycleMean.Text = meanResults.ToString("F6");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Measure transition.
        /// </summary>
        private void TransitionMeasurement()
        {
            try
            {
                WaveformMeasurements.TransitionMeasurement(_ys, _increment, _stateSetting, _edgePolarity, _refLevelSetting, uiComboBox_PulseIndex.SelectedIndex + 1, out double slope, out double transitionDuration, out TransitionInfo preTransInfo, out TransitionInfo postTransInfo, out MeasurementInfo measInfo);

                // Set EasyChartX Cursor Values
                _edgeStartCursor.XValue = measInfo.StartTime;
                _edgeEndCursor.XValue = measInfo.EndTime;
                _highLevelCursor.YValue = measInfo.PulseReferenceLevel.High;
                _lowLevelCursor.YValue = measInfo.PulseReferenceLevel.Low;

                uiTextBox_PreOvershoot.Text = preTransInfo.Overshoot.ToString("F6");
                uiTextBox_PreUndershoot.Text = preTransInfo.Undershoot.ToString("F6");
                uiTextBox_PostOvershoot.Text = postTransInfo.Overshoot.ToString("F6");
                uiTextBox_PostUndershoot.Text = postTransInfo.Undershoot.ToString("F6");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}